﻿using CK.Sprite.CrossCutting;
using CK.Sprite.Framework;
using CK.Sprite.ThirdContract;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CK.Sprite.Form.Core
{
#if DEBUG
    [Authorize]
#else
     [Authorize]
#endif
    public class RuntimeAppService : AppService, IRuntimeAppService, IFormThirdServiceAppService
    {
        public SpriteFormLocalCache SpriteFormLocalCache => LazyGetRequiredService(ref _spriteFormLocalCache);
        private SpriteFormLocalCache _spriteFormLocalCache;

        public SpriteViewLocalCache SpriteViewLocalCache => LazyGetRequiredService(ref _spriteViewLocalCache);
        private SpriteViewLocalCache _spriteViewLocalCache;

        public DictDbFrameworkCache DictDbFrameworkCache => LazyGetRequiredService(ref _dictDbFrameworkCache);
        private DictDbFrameworkCache _dictDbFrameworkCache;

        private readonly RuntimeService _runtimeService;
        public RuntimeAppService(RuntimeService runtimeService)
        {
            _runtimeService = runtimeService;
        }

        [FormIntercept]
        public async Task<object> DoRuntimeMethod(JObject paramObject)
        {
            return await _runtimeService.CallRuntimeMethod(paramObject);
        }

        public async Task<List<RemoteSourceDto>> GetDictItemRemoteInfo(string dictCode)
        {
            var results = new List<RemoteSourceDto>();
            var allDictInfos = DictDbFrameworkCache.GetBusinessCacheDtos();
            var findDict = allDictInfos.FirstOrDefault(r => r.Id == dictCode);
            if(findDict == null)
            {
                return results;
            }
            else
            {
                foreach(var dictItemDto in findDict.DictItemDtos)
                {
                    results.Add(new RemoteSourceDto()
                    {
                        Name = dictItemDto.Name,
                        Value = dictItemDto.Code
                    });
                }
            }

            return results;
        }

        #region 远程控件调用

        public async Task<List<ValueName>> DoGetRemoteSelectCall(DoGetRemoteSelectCallInput selectCallInput)
        {
            return await _runtimeService.DoGetRemoteSelectCall(selectCallInput.applicationCode, selectCallInput.objectName, selectCallInput.filter, selectCallInput.isAll);
        }

        public async Task<List<ValueName>> DoGetByIds(DoGetByIdsInput byIdsInput)
        {
            return await _runtimeService.DoGetByIds(byIdsInput.applicationCode, byIdsInput.objectName, byIdsInput.ids, byIdsInput.script);
        }

        public async Task<List<ValueName>> DoGetUserByIds(DoGetUserByIdsInput userByIdsInput)
        {
            return await _runtimeService.DoGetUserByIds(userByIdsInput.ids, userByIdsInput.script);
        }

        #endregion

        #region 导入Excel相关

        public async Task ImportExcel(string applicationCode, JArray importJArray, JArray updateJArray, SpriteObjectDto spriteObjectDto)
        {
            await _runtimeService.ImportExcel(applicationCode, importJArray, updateJArray, spriteObjectDto);
        }

        public async Task<JObject> DoGetUniqInfos(string applicationCode, SpriteObjectDto spriteObjectDto, string uniqFieldInfo, List<string> uniqValues)
        {
            return await _runtimeService.DoGetUniqInfos(applicationCode, spriteObjectDto, uniqFieldInfo, uniqValues);
        }

        #endregion

        #region 客户端获取视图表单定义信息

        public async Task<FormViewVueInfos> GetFormVueInfos(string applicationCode, Guid id, string dictVersion)
        {
            var formViewVueInfos = new FormViewVueInfos();

            var spriteFormCaches = SpriteFormLocalCache.GetAllDict(applicationCode);
            var spriteViewCaches = SpriteViewLocalCache.GetAllDict(applicationCode);

            CalculateFormViewVueInfo(formViewVueInfos, spriteFormCaches, spriteViewCaches, id, true);

            var newDictVersion = DictDbFrameworkCache.GetCurrentCacheVersion();
            if (string.IsNullOrEmpty(dictVersion) || dictVersion != newDictVersion)
            {
                formViewVueInfos.DictVersion = newDictVersion;
                formViewVueInfos.Dicts = DictDbFrameworkCache.GetBusinessCacheDtos();
            }

            return await Task.FromResult(formViewVueInfos);
        }

        public async Task<FormViewVueInfos> GetViewVueInfos(string applicationCode, Guid id, string dictVersion)
        {
            var formViewVueInfos = new FormViewVueInfos();

            var spriteFormCaches = SpriteFormLocalCache.GetAllDict(applicationCode);
            var spriteViewCaches = SpriteViewLocalCache.GetAllDict(applicationCode);

            CalculateFormViewVueInfo(formViewVueInfos, spriteFormCaches, spriteViewCaches, id, false);

            var newDictVersion = DictDbFrameworkCache.GetCurrentCacheVersion();
            if(string.IsNullOrEmpty(dictVersion) || dictVersion != newDictVersion)
            {
                formViewVueInfos.DictVersion = newDictVersion;
                formViewVueInfos.Dicts = DictDbFrameworkCache.GetBusinessCacheDtos();
            }

            return await Task.FromResult(formViewVueInfos);
        }

        [AllowAnonymous]
        public async Task<DictWrap> GetDictInfos(string version)
        {
            DictWrap result = new DictWrap();
            var newDictVersion = DictDbFrameworkCache.GetCurrentCacheVersion();
            if (string.IsNullOrEmpty(version) || version != newDictVersion)
            {
                result.Version = newDictVersion;
                result.Dicts = DictDbFrameworkCache.GetBusinessCacheDtos();
            }
            else
            {
                result.Version = version;
            }

            return await Task.FromResult(result);
        }

        public async Task<FormViewVueInfos> GetFormViewVueInfoByRelation(RelationInfoInputs relationInfoInputs)
        {
            var formViewVueInfos = new FormViewVueInfos();
            var formViewVueInfoResult = await GetFormVueInfos(relationInfoInputs.ApplicationCode, relationInfoInputs.FormId, relationInfoInputs.DictVersion);
            foreach (var formData in formViewVueInfoResult.FormDatas)
            {
                var relationData = relationInfoInputs.RelationInfos.FirstOrDefault(r => r.Id == formData.Id && r.RelationType == 1);
                if (relationData == null || relationData.Version != formData.Version)
                {
                    formViewVueInfos.FormDatas.Add(formData);
                }
            }

            foreach (var viewData in formViewVueInfoResult.ViewDatas)
            {
                var relationData = relationInfoInputs.RelationInfos.FirstOrDefault(r => r.Id == viewData.Id && r.RelationType == 2);
                if (relationData == null || relationData.Version != viewData.Version)
                {
                    formViewVueInfos.ViewDatas.Add(viewData);
                }
            }

            formViewVueInfos.DictVersion = formViewVueInfoResult.DictVersion;
            formViewVueInfos.Dicts = formViewVueInfoResult.Dicts;

            return formViewVueInfos;
        }

        private void CalculateFormViewVueInfo(FormViewVueInfos formViewVueInfos, Dictionary<Guid, SpriteFormVueDto> spriteFormVueDtos, Dictionary<Guid, SpriteViewVueDto> spriteViewVueDtos, Guid id, bool isForm)
        {
            if (isForm)
            {
                spriteFormVueDtos.TryGetValue(id, out var spriteFormVueDto);
                if (spriteFormVueDtos.ContainsKey(id) && !formViewVueInfos.FormDatas.Exists(r => r.Id == spriteFormVueDto.Id))
                {
                    formViewVueInfos.FormDatas.Add(spriteFormVueDto);
                    foreach (var relationInfo in (spriteFormVueDto.RelationInfos as List<RelasionInfo>))
                    {
                        CalculateFormViewVueInfo(formViewVueInfos, spriteFormVueDtos, spriteViewVueDtos, relationInfo.Id, relationInfo.RelationType == 1);
                    }
                }
            }
            else
            {
                spriteViewVueDtos.TryGetValue(id, out var spriteViewVueDto);
                if (spriteViewVueDto != null && !formViewVueInfos.FormDatas.Exists(r => r.Id == spriteViewVueDto.Id))
                {
                    formViewVueInfos.ViewDatas.Add(spriteViewVueDto);
                    foreach (var relationInfo in (spriteViewVueDto.RelationInfos as List<RelasionInfo>))
                    {
                        CalculateFormViewVueInfo(formViewVueInfos, spriteFormVueDtos, spriteViewVueDtos, relationInfo.Id, relationInfo.RelationType == 1);
                    }
                }
            }
        }

        #endregion
    }
}
